﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32;

namespace Bookvar.UpdateMonitor
{
	internal static class Program
	{
		private const uint ERROR_SUCCESS = 0;
		private const uint INFINITE = 0xffffffff;
		private const uint WAIT_ABANDONED = 0x00000080;
		private const uint WAIT_OBJECT_0 = 0;
		private const uint WAIT_TIMEOUT = 0x00000102;
		private const uint WAIT_FAILED = 0xffffffff;
		private const uint STILL_ACTIVE = 259;

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        public static int Main( string[] args )
		{
			try
			{
				int returnValue = MainImpl( args );
				return returnValue;
			}

			catch ( Exception ex )
			{
				Console.WriteLine( ex.ToString() );
				return 1;
			}
		}

		private static int MainImpl( string[] args )
		{
			Console.WriteLine( "Command line is: " + Environment.CommandLine );

			//uint dwResult = ERROR_SUCCESS;
			bool bResult = true;

			if ( args.Length != 1 )
			{
				return 1;
			}

			ulong uHandleValue = ulong.Parse( args[ 0 ], CultureInfo.InvariantCulture );
			Console.WriteLine( "Handle value is: " + uHandleValue );

			long handleValue = unchecked( (long) uHandleValue );
			IntPtr hProcess = new IntPtr( handleValue );

			// Wait for the given process to finish
			Console.Write( "Waiting for process to exit ... " );
			//dwResult = NativeMethods.WaitForSingleObject( hProcess, INFINITE );
			Console.WriteLine( "done" );

			// Get its exit code
			uint dwExitCode = 0;
			Console.Write( "Retrieving process exit code ... " );
			bResult = NativeMethods.GetExitCodeProcess( hProcess, out dwExitCode );

			if ( !bResult )
			{
				int error = Marshal.GetLastWin32Error();
				throw new Win32Exception( error, "GetExitCodeProcess returned false, and error " + error );
			}

			if ( dwExitCode == STILL_ACTIVE )
			{
				throw new InvalidOperationException( "process was still active even though WaitForSingleObject() completed" );
			}
//
//			if (dwExitCode != 0)
//			{
//				throw new ApplicationException("process did not complete successfully, its exit code was " + dwExitCode);
//			}

			Console.WriteLine( "exit code was " + dwExitCode );

			Console.Write( @"Retrieving install directory from registry, HKLM \ Software \ Avaxo \ Bookvar \ InstallDir... " );

			const string subKeyName = @"SOFTWARE\Avaxo\Bookvar";
			RegistryKey key = Registry.LocalMachine.OpenSubKey( subKeyName, false );

			if ( key == null )
			{
				throw new InvalidOperationException( "registry key HKLM\\" + subKeyName +
				                                " could not be opened: OpenSubKey returned null" );
			}

			const string valueName = "InstallDir";
			object targetDirObj = key.GetValue( valueName, null, RegistryValueOptions.DoNotExpandEnvironmentNames );

			if ( targetDirObj == null )
			{
				throw new InvalidOperationException( valueName + " value was retrieved from registry as null" );
			}

			string targetDir = targetDirObj as string;

			if ( targetDir == null )
			{
				throw new InvalidOperationException( valueName + " was not a string; its retrieved .NET type was " +
				                                targetDirObj.GetType().Name + ", and ToString() value was " + targetDirObj );
			}

			Console.WriteLine( targetDir );

			// Validate as dir name
			Console.Write( "Validating directory name ... " );
			if ( !Directory.Exists( targetDir ) )
			{
				throw new InvalidOperationException( "Directory.Exists(" + targetDir + ") returned false" );
			}

			Console.WriteLine( "done" );

			// Determine the exe that we will be launching
			Console.Write( "Building executable path to launch: " );

			const string bookvarExe = "Bookvar.exe";
			string bookvarExePath = Path.Combine( targetDir, bookvarExe );

			Console.WriteLine( bookvarExePath );

			// Validate as path/exe name
			Console.Write( "Validating path name ... " );

			if ( !File.Exists( bookvarExePath ) )
			{
				throw new InvalidOperationException( "File.Exists(" + bookvarExePath + ") returned false" );
			}

			// Launch it
			Console.Write( "Executing: " );
			ProcessStartInfo psi = new ProcessStartInfo( bookvarExePath );
			psi.UseShellExecute = true;
			psi.WorkingDirectory = targetDir;

			Process process = Process.Start( psi );

			Console.WriteLine( "success. PID = " + process.Id );
			process.Dispose();

			return 0;
		}
	}
}